﻿import base = require('./base');
/**
* 类型名称属性名
*/
export const typeNamePropertyName: string = "$type";

/**
* 基础插件对象:所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述
*/
export interface addonObject {
    /** 类型名称，序列化/反序列化时用于保存类型的原型 */
    $type?: string;
    /** 工厂 */
    $factory?: factory;
    /** 元数据：模块/命名空间名称 */
    $module?: string;
    /** 元数据：插件名称 */
    $addonName?: string;
    /** 元数据：插件描述 */
    $addonDescription?: string;
    /** 扩展属性 */
    [id: string]: any

    /**
        * 事件：指定类型后
        */
    onAssignedType?(): void;
}

/**
* 工厂接口
*/
export interface factory extends addonObject {
    getValue?(): any;
}
/**
 * 全局插件列表
 */
export class globalAddons {

};

/**
* 判断某个对象是否为Factory
* @param testObject 待测试的对象
*/
export function isFactory(testObject: any): testObject is factory {
    return (<factory>testObject).getValue != undefined
}
/**
 * 模块名称
 */
const moduleName = "kf";
//******************** 装饰器 *********************
/**
 * 插件装饰器：用此装饰过的插件会将构造函数添加到插件类型列表中，便于检索
 * @param name 插件名称
 * @param description 插件描述
 */
export function addon(name: string, description?: string, moduleName?: string) {
    return function (target: any) {
        target.prototype.$module = moduleName;
        target.prototype.$addonName = name;
        target.prototype.$addonDescription = description;

        let fullName = base.reflect.getTypeFullName(target);
        console.log(`插件${fullName}加载成功.`);
        globalAddons[fullName] = target;
    };
}

//********************   实体对象   *********************
/**
 * 基础插件对象:所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述
 */
@addon("基础插件对象",
    "所有实体对象的基类，实现了ID，Name和Description，其中ID是对象的唯一标识，Name是对象的好记的名称，Description是对象的描述",
    moduleName)
export class baseObject implements addonObject {
    /** 类型名称，序列化/反序列化时用于保存类型的原型 */
    $type?: string;
    /** 类型 */
    $constructor?: base.type<addonObject>;
    /** 元数据：模块/命名空间名称 */
    $module?: string;
    /** 元数据：插件名称 */
    $addonName?: string;
    /** 元数据：插件描述 */
    $addonDescription?: string;
    /** 扩展属性 */
    [id: string]: any
    /**
     * 事件：指定类型后
     */
    onAssignedType?(): void { }
}

/**
 * 应用对象:支持直接对象和工厂对象，如果设置的直接对象，则Value直接返回直接对象；否则返回工厂的GetValue方法
 */
@addon("引用对象",
    "支持直接对象和工厂对象，如果设置的直接对象，则Value直接返回直接对象；否则返回工厂的GetValue方法",
    moduleName)
export class ref<T> extends baseObject {
    constructor(public innerObject?: any) {
        super();
    }

    Value?(): T {
        if (isFactory(this.innerObject)) {
            return (<factory>this.innerObject).getValue();
        } else {
            return this.innerObject;
        }
    }
}

/**
 * 对象工厂: 对象的直接引用
 */
@addon("对象工厂",
    "对象的直接引用",
    moduleName)
export class objectFactory extends baseObject implements factory {
    constructor(public objectReference?: any) {
        super();
    }
    getValue?(): any {
        if (!this.objectReference)
            this.build();

        return this.objectReference!;
    }
    build?(): void {
    }
}

/**
 * Json工厂: 通过JSONP字符串创建对象
 */
@addon("Json工厂",
    "通过JSONP字符串创建对象",
    moduleName)
export class jsonFactory extends baseObject implements factory {
    constructor(public jsonString?: string) {
        super();
        if (jsonString) {
            this.build();
        }
    }
    getValue?(): any {
        return addonDeserialize(this.jsonString);
    }
}

/**
 * 插件工厂：根据插件ID获取插件
 */
@addon("插件工厂",
    "根据插件",
    moduleName)
export class addonFactory extends baseObject implements factory {
    constructor(public rootObject?: any, public addonID?: string) {
        super();
    }

    getValue?(): any {
        return findAddonByID(this.rootObject, this.addonID);
    }
}

/**
 * 插件实例化
 * @param typeName 插件类型名称
 */
export function newInstance(typeName: string): any {
    let classType = window[typeName];
    let result = new classType();
    return result;
}

/**
 * 根据插件ID查找插件
 * @param rootObject 根对象
 * @param addonID 插件ID
 */
export function findAddonByID(rootObject: any, addonID: string): any {
    if (rootObject.ID == addonID) {
        return rootObject
    }

    // 查找子属性
    for (let property in rootObject) {
        let childAddon = findAddonByID(rootObject[property], addonID);
        if (childAddon)
            return childAddon;
    }

    return undefined;
}

/**
* 将对象中的类型信息取出并更改对象的类型
* @param rootObject 待获取类型的对象
*/
export function fetchAddonProtoType(rootObject: Object): void {
    // 获取子属性的类型信息
    for (let property in rootObject) {
        let properyValue = rootObject[property];
        if (properyValue instanceof Object && !(properyValue instanceof Function)) {
            fetchAddonProtoType(properyValue);
        }
    }

    // 先通过$constructor获取类型
    let classType = rootObject.constructor;
    if (!classType || classType == Object) {
        // 然后通过$type获取类型
        let typeName = rootObject[typeNamePropertyName];
        if (typeName) {
            classType = getAddonTypeByFullName(typeName);
        }
    }
    if (classType) {
        base.reflect.assignType(rootObject, classType);
    }
}
/**
* 设置类型信息到对象中
* @param rootObject 待设置类型的对象
*/
export function setAddonTypeInfo(addonObject: Object): void {
    // 设置子属性的类型信息
    for (let property in addonObject) {
        let properyValue = addonObject[property];
        if (properyValue instanceof Object) {
            setAddonTypeInfo(properyValue);
        }
    }
    let typeName = base.reflect.getTypeFullName(addonObject);
    if (typeName != "Object") {
        addonObject[typeNamePropertyName] = typeName;
    }
}

/**
* 根据类型名称获取类型
* @param typeName 类型名称
*/
export function getAddonTypeByFullName(typeName: string): any {
    return globalAddons[typeName];
}

/**
* 插件序列化
* @param origion 待序列化的原始对象
*/
export function addonSerialize(origin: Object): string {
    setAddonTypeInfo(origin);
    return JSON.stringify(origin);
}

/**
    * 插件反序列化
    * @param jsonString json字符串
    */
export function addonDeserialize(jsonString: string): any {
    let result = JSON.parse(jsonString);
    fetchAddonProtoType(result);
    return result;
}

/**
    * 反序列化
    * @param classType 类型
    * @param jsonString json字符串
    */
export function addonDeserialize_T<T>(classType: base.type<T>, jsonString: string): T {
    let result: any = JSON.parse(jsonString);
    base.reflect.assignType(result, classType);
    return result;
}

/**
* 转换为字符串，如果是函数，获取函数脚本，如果是对象，获取Json
* @param origin
*/
export function toString(origin: any): string {
    if (origin instanceof Function) {
        return origin.toString();
    }
    return addonSerialize(origin);
}

/**
 * 应用类
 */
@addon("应用设置", "包含各种资源的主应用实体对象", moduleName)
export class appSetting extends baseObject {
}
